namespace Skymate.Lyjt.Core
{
    using System.Collections.Generic;
    using System.Linq;

    public class ProtocolAnalysis : IProtocolAnalysis
    {
        public bool CheckSumIsRight(byte[] dataBuffer, byte checkSum)
        {
            var check = this.GenerateChecksum(dataBuffer);

            return check == checkSum;
        }

        public byte GenerateChecksum(byte[] dataBuffer)
        {
            return dataBuffer.Aggregate<byte, byte>(0x00, (current, b) => (byte)(current + b));
        }

        public int GetReadDataLength(byte[] readBuffer)
        {
            int dataLength;
            var bufferLength = readBuffer.Length;
            if (readBuffer[bufferLength - 3] == 0xDB)
            {
                dataLength = bufferLength - 1 - 1 - 2;
            }
            else
            {
                dataLength = bufferLength - 1 - 1 - 1;
            }

            return dataLength;
        }

        public byte GetReadBufferCheckSum(byte[] readBuffer)
        {
            byte check = 0x00;
            var bufferLength = readBuffer.Length;
            if (readBuffer[bufferLength - 3] == 0xDB)
            {
                // 校验码可能是C0或DB
                switch (readBuffer[bufferLength - 2])
                {
                    case 0xDC:
                        check = 0xC0;
                        break;
                    case 0xDD:
                        check = 0xDB;
                        break;
                    case 0xDA:
                        check = 0x41;
                        break;
                }
            }
            else
            {
                check = readBuffer[bufferLength - 2];
            }

            return check;
        }

        public byte[] Encry(byte[] buffer)
        {
            IList<byte> result = new List<byte>();

            foreach (var b in buffer)
            {
                switch (b)
                {
                    case 0xC0:
                        result.Add(0xDB);
                        result.Add(0xDC);
                        break;
                    case 0xDB:
                        result.Add(0xDB);
                        result.Add(0xDD);
                        break;
                    case 0x41:
                        result.Add(0xDB);
                        result.Add(0xDA);
                        break;
                    default:
                        result.Add(b);
                        break;
                }
            }

            return result.ToArray();
        }

        public byte[] EncryData(byte[] buffer)
        {
            List<byte> result = new List<byte>() { 0xC0, 0xC0 };
            var encry = this.Encry(buffer);
            var checksum = this.GenerateChecksum(encry);
            IList<byte> checks = new List<byte>();
            switch (checksum)
            {
                case 0xC0:
                    checks.Add(0xDB);
                    checks.Add(0xDC);
                    break;
                case 0xDB:
                    checks.Add(0xDB);
                    checks.Add(0xDD);
                    break;
                case 0x41:
                    checks.Add(0xDB);
                    checks.Add(0xDA);
                    break;
                default:
                    checks.Add(checksum);
                    break;
            }

            result.InsertRange(1, encry);
            result.InsertRange(1 + encry.Length, checks);

            return result.ToArray();
        }

        /// <summary>
        /// 读取数据，读取后的数据是经过解密的数据
        /// </summary>
        /// <param name="readBuffer">读取的数据</param>
        /// <returns>解密后的数据</returns>
        public byte[] Read(byte[] readBuffer)
        {
            if (readBuffer.Length < 2)
            {
                return new byte[] { };
            }

            if (readBuffer[0] != 0xC0 || readBuffer[readBuffer.Length - 1] != 0xC0)
            {
                return new byte[] { };
            }

            // readbuffer 是包含了头和尾 的
            var check = this.GetReadBufferCheckSum(readBuffer);
            var dataLength = this.GetReadDataLength(
                readBuffer);
            var dataBuffer = readBuffer.Range(1, dataLength);

            var generateCheck = this.GenerateChecksum(dataBuffer);

            return generateCheck != check ? new byte[] { } : this.DecryptData(dataBuffer);
        }

        public byte[] DecryptData(byte[] dataBuffer)
        {
            if (dataBuffer.Length <= 1)
            {
                return dataBuffer;
            }
            
            // 解析数据 
            // TODO:反向解析数据也要提炼方法
            IList<byte> dataList = new List<byte>();

            for (int i = 0; i < dataBuffer.Length - 1; i++)
            {
                if (dataBuffer[i] == 0xDB && dataBuffer[i + 1] == 0xDC)
                {
                    dataList.Add(0xC0);
                    i++;
                }
                else if (dataBuffer[i] == 0xDB && dataBuffer[i + 1] == 0xDD)
                {
                    dataList.Add(0xDB);
                    i++;
                }
                else if (dataBuffer[i] == 0xDB && dataBuffer[i + 1] == 0xDA)
                {
                    dataList.Add(0x41);
                    i++;
                }
                else
                {
                    dataList.Add(dataBuffer[i]);
                }
            }

            if (dataBuffer[dataBuffer.Length - 2] != 0xDB)
            {
                dataList.Add(dataBuffer[dataBuffer.Length - 1]);    
            }

            return dataList.ToArray();
        }
    }
}